package com.mxpio.erp.technology.service.impl;

import com.googlecode.aviator.AviatorEvaluator;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.technology.entity.*;
import com.mxpio.erp.common.technology.service.BomInfoService;
import com.mxpio.erp.common.technology.vo.BomTreeVO;
import com.mxpio.erp.common.technology.vo.ConsumptionVO;
import com.mxpio.erp.common.technology.vo.VersionVO;
import com.mxpioframework.common.exception.MBootException;
import com.mxpioframework.common.vo.Result;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.system.service.impl.BaseServiceImpl;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class BomInfoServiceImpl extends BaseServiceImpl<BomInfo> implements BomInfoService {

    @Transactional(
            readOnly = false
    )
    @Override
    public List<BomInfo> listByDate(String dateStr){
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        Date date = null;
        try{
            date = dateFormat.parse(dateStr);
        }
        catch (Exception e){
            throw new MBootException("日期"+dateStr+"不合法");
        }
        List<BomInfo> bomInfoList = JpaUtil.linq(BomInfo.class).lessThanOrEqualTo("beginTime",date).greaterThan("endTime",date).list();
        if(CollectionUtils.isEmpty(bomInfoList)){
            return bomInfoList;
        }

        for(BomInfo bomInfo:bomInfoList){
            List<BomInfoLine> bomInfoLineList = JpaUtil.linq(BomInfoLine.class).equal("bomId",bomInfo.getParentCode()).list();
            if(CollectionUtils.isEmpty(bomInfoLineList)){
                continue;
            }
            Date bomBeginTime = bomInfo.getBeginTime();
            if(bomInfo.getBomInfoLineList()==null){
                bomInfo.setBomInfoLineList(new ArrayList<>());
            }
            for(BomInfoLine line:bomInfoLineList){
                if(line.getBeginTime().compareTo(bomBeginTime)<=0&&line.getEndTime().compareTo(bomBeginTime)>=0){
                    bomInfo.getBomInfoLineList().add(line);
                }
            }
        }
        return bomInfoList;
    }

    @Transactional(
            readOnly = false
    )
    @Override
    public Result<BomInfo> updateBomStatus(BomInfo bomInfo, OrderStatusEnums.BomStatus bomStatus){
        bomInfo.setUseType(bomStatus.getStatusCode());
        this.update(bomInfo);
        return Result.OK();
    }


    @Transactional(
            readOnly = false
    )
    @Override
    public BomInfo listBom(String itemCode, VersionVO vo){
        List<Item> itemList = JpaUtil.linq(Item.class).equal("itemCode",itemCode).equal("itemSource","1").list();
        if(CollectionUtils.isEmpty(itemList)){
            return new BomInfo();
        }
        Item item = itemList.get(0);
        List<BomInfo> bomInfoList;
        if(vo.getDate() != null){
            bomInfoList = JpaUtil.linq(BomInfo.class).equal("parentCode",itemCode).lessThanOrEqualTo("beginTime",vo.getDate()).greaterThan("endTime",vo.getDate()).list();
        }
        else if(StringUtils.isNotBlank(vo.getVersion())){
            bomInfoList = JpaUtil.linq(BomInfo.class).equal("parentCode",itemCode).equal("version",vo.getVersion()).list();
        }
        else{
            bomInfoList = JpaUtil.linq(BomInfo.class).equal("parentCode",itemCode).equal("primaryBom","1").list();
        }

        BomInfo bomInfo;
        if(CollectionUtils.isEmpty(bomInfoList)){
            bomInfo = new BomInfo();
            bomInfo.setParentCode(item.getItemCode());
            bomInfo.setParentName(item.getItemName());
            bomInfo.setParentGroup(item.getItemGroupCode());
            bomInfo.setParentSpec(item.getItemSpec());
            bomInfo.setParentUnit(item.getUnitCode());
        }
        else{
            bomInfo = bomInfoList.get(0);
            List<BomInfoLine> lineList = JpaUtil.linq(BomInfoLine.class).equal("bomId",bomInfo.getParentCode()).lessThanOrEqualTo("beginTime",bomInfo.getBeginTime()).greaterThan("endTime",bomInfo.getBeginTime()).list();
            bomInfo.setBomInfoLineList(lineList);
        }
        return bomInfo;
    }
    @Override
    @Transactional(
            readOnly = false
    )
    public List<BomInfo> listHistory(String itemCode){
        List<BomInfo> bomInfoList = JpaUtil.linq(BomInfo.class).equal("parentCode",itemCode).asc("beginTime").list();
        if(CollectionUtils.isEmpty(bomInfoList)){
            return bomInfoList;
        }
        List<BomInfoLine> bomInfoLineList = JpaUtil.linq(BomInfoLine.class).equal("bomId",itemCode).list();
        if(CollectionUtils.isEmpty(bomInfoLineList)){
            return bomInfoList;
        }

        for(BomInfo bomInfo:bomInfoList){
            Date bomBeginTime = bomInfo.getBeginTime();
            if(bomInfo.getBomInfoLineList()==null){
                bomInfo.setBomInfoLineList(new ArrayList<>());
            }
            for(BomInfoLine line:bomInfoLineList){
                if(line.getBeginTime().compareTo(bomBeginTime)<=0&&line.getEndTime().compareTo(bomBeginTime)>=0){
                    bomInfo.getBomInfoLineList().add(line);
                }
            }
        }

        /*Map<Date,BomInfo> bomInfoMap = JpaUtil.index(bomInfoList,"beginTime");
        for(BomInfoLine line:bomInfoLineList){
            BomInfo bomInfo = bomInfoMap.get(line.getBeginTime());
            if(bomInfo==null){
                continue;
            }
            if(bomInfo.getBomInfoLineList()==null){
                bomInfo.setBomInfoLineList(new ArrayList<>());
            }
            bomInfo.getBomInfoLineList().add(line);
        }*/
        return bomInfoList;
    }

    @Override
    @Transactional(
            readOnly = false
    )
    public Page<BomInfo> page(Pageable page, Criteria c){

        Page<Item> itemPage = JpaUtil.linq(Item.class).where(c).equal("itemSource","1").paging(page);
        Long count = JpaUtil.linq(Item.class).where(c).equal("itemSource","1").count();
        List<Item> itemList = itemPage.getContent();
        Set<String> itemCodes = JpaUtil.collect(itemList, "itemCode");
        List<BomInfo> bomInfoList= JpaUtil.linq(BomInfo.class).in("parentCode",itemCodes).equal("primaryBom","1").list();
        Map<String,BomInfo> bomMap = JpaUtil.index(bomInfoList,"parentCode");
        List<BomInfo> returnList = new ArrayList<>();
        for(Item item:itemList){
            BomInfo bomInfo = bomMap.get(item.getItemCode());
            if(Objects.isNull(bomInfo)){
                bomInfo = new BomInfo();
            }
            bomInfo.setParentCode(item.getItemCode());
            bomInfo.setParentName(item.getItemName());
            bomInfo.setParentGroup(item.getItemGroupCode());
            bomInfo.setParentSpec(item.getItemSpec());
            bomInfo.setParentUnit(item.getUnitCode());
            bomInfo.setParentDrawingNo(item.getDrawingNo());
            returnList.add(bomInfo);
        }
        return new PageImpl<>(returnList, page, count);
    }

    @Override
    @Transactional(
            readOnly = false
    )
    public ImmutablePair<String,String> consumption(ConsumptionVO vo){
        List<ItemMaterialProp> props = JpaUtil.linq(ItemMaterialProp.class).equal("code",vo.getItemCode()).equal("propType","item").list();
        if(CollectionUtils.isEmpty(props)){
            String msg = "未找到编码为["+vo.getItemCode()+"]的物料属性";
            return new ImmutablePair<>(null,msg);
        }

        ItemMaterialProp prop = props.get(0);

        List<ConsumptionExp> expList = JpaUtil.linq(ConsumptionExp.class).equal("materialType",prop.getMaterialType()).list();

        if(CollectionUtils.isEmpty(expList)){
            return new ImmutablePair<>("0",null);
        }

        Map<String, Object> env = new HashMap<>();
        env.put("L",vo.getMakeLength());
        env.put("q",vo.getMakeNum());
        env.put("s",vo.getMakeArea());
        env.put("a",prop.getMaterialDensity());
        env.put("R",prop.getMaterialDiameter());
        env.put("r",prop.getMaterialThickness());


        BigDecimal result = new BigDecimal(AviatorEvaluator.execute(expList.get(0).getExpression(), env).toString()).setScale(2, RoundingMode.HALF_UP);

        return new ImmutablePair<>(result.toPlainString(),null);
    }

    @Transactional
    @Override
    public void clacAll(){
        List<BomInfoLine> bomInfoLines = JpaUtil.linq(BomInfoLine.class).le("itemConsumption", BigDecimal.ZERO).list();
        if(CollectionUtils.isNotEmpty(bomInfoLines)){
            for(BomInfoLine line:bomInfoLines){
                ConsumptionVO vo = new ConsumptionVO();
                vo.setItemCode(line.getItemCode());
                vo.setMakeLength(line.getMakeLength());
                vo.setMakeArea(line.getMakeArea());
                vo.setMakeNum(line.getMakeNum());
                ImmutablePair<String,String> pair = this.consumption(vo);
                if(StringUtils.isBlank(pair.getRight())){
                    line.setItemConsumption(new BigDecimal(pair.getLeft()).setScale(2,RoundingMode.HALF_UP));
                    JpaUtil.update(line);
                }

            }

        }
    }
    @Transactional
    @Override
    public List<BomInfoLine> listSub(BomTreeVO vo){
        List<BomInfoLine> bomInfoLines = JpaUtil.linq(BomInfoLine.class).equal("bomId",vo.getItemCode()).lessThanOrEqualTo("beginTime",vo.getDate()).greaterThan("endTime",vo.getDate()).list();
        if(CollectionUtils.isNotEmpty(bomInfoLines)){
            Set<String> itemSet = bomInfoLines.stream().map(BomInfoLine::getItemCode).collect(Collectors.toSet());
            List<BomInfoLine> subLines = JpaUtil.linq(BomInfoLine.class).in("bomId",itemSet).lessThanOrEqualTo("beginTime",vo.getDate()).greaterThan("endTime",vo.getDate()).list();
            Set<String> existsItemSet = subLines.stream().map(BomInfoLine::getBomId).collect(Collectors.toSet());
            for(BomInfoLine line:bomInfoLines){
                if(existsItemSet.contains(line.getItemCode())){
                    line.setHasSub(true);
                }
                else{
                    line.setHasSub(false);
                }
            }
        }

        return bomInfoLines;
    }
}
